home *** CD-ROM | disk | FTP | other *** search
/ Isometric Game Programming with DirectX 7.0 / Isometric Game Programming.iso / directx / dxf / samples / multimedia / directplay / voiceconnect / voiceconnect.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2000-11-04  |  53.7 KB  |  1,363 lines

  1. //----------------------------------------------------------------------------
  2. // File: VoiceConnect.cpp
  3. //
  4. // Desc: The main file for VoiceConnect that shows how use DirectPlay along 
  5. //       with DirectPlayVoice to allow talking in a conference situation. 
  6. //
  7. // Copyright (c) 1999-2000 Microsoft Corp. All rights reserved.
  8. //-----------------------------------------------------------------------------
  9. #define STRICT
  10. #include <windows.h>
  11. #include <basetsd.h>
  12. #include <dxerr8.h>
  13. #include <dplay8.h>
  14. #include <dplobby8.h>
  15. #include <dvoice.h>
  16. #include <commctrl.h>
  17. #include <cguid.h>
  18. #include "NetConnect.h"
  19. #include "NetVoice.h"
  20. #include "DXUtil.h"
  21. #include "resource.h"
  22.  
  23.  
  24.  
  25.  
  26. //-----------------------------------------------------------------------------
  27. // Player context locking defines
  28. //-----------------------------------------------------------------------------
  29. CRITICAL_SECTION g_csPlayerContext;
  30. #define PLAYER_LOCK()                   EnterCriticalSection( &g_csPlayerContext ); 
  31. #define PLAYER_ADDREF( pPlayerInfo )    if( pPlayerInfo ) pPlayerInfo->lRefCount++;
  32. #define PLAYER_RELEASE( pPlayerInfo )   if( pPlayerInfo ) { pPlayerInfo->lRefCount--; if( pPlayerInfo->lRefCount <= 0 ) SAFE_DELETE( pPlayerInfo ); }
  33. #define PLAYER_UNLOCK()                 LeaveCriticalSection( &g_csPlayerContext );
  34.  
  35.  
  36. //-----------------------------------------------------------------------------
  37. // Defines, and constants
  38. //-----------------------------------------------------------------------------
  39. #define DPLAY_SAMPLE_KEY        TEXT("Software\\Microsoft\\DirectX DirectPlay Samples")
  40. #define MAX_PLAYER_NAME         14
  41. #define WM_APP_DISPLAY_PLAYERS  (WM_APP + 0)
  42.  
  43. // This GUID allows DirectPlay to find other instances of the same game on
  44. // the network.  So it must be unique for every game, and the same for 
  45. // every instance of that game.  // {FCD4761E-2B9C-4478-B7EA-D9E18E6E2AAC}
  46. GUID g_guidApp = { 0xfcd4761e, 0x2b9c, 0x4478, { 0xb7, 0xea, 0xd9, 0xe1, 0x8e, 0x6e, 0x2a, 0xac } };
  47.  
  48.  
  49.  
  50.  
  51. //-----------------------------------------------------------------------------
  52. // Global variables
  53. //-----------------------------------------------------------------------------
  54. struct APP_PLAYER_INFO
  55. {
  56.     LONG  lRefCount;                        // Ref count so we can cleanup when all threads 
  57.                                             // are done w/ this object
  58.     DPNID dpnidPlayer;                      // DPNID of player
  59.     BOOL  bTalking;                         // Is the player talking
  60.     BOOL  bHalfDuplex;                      // If true, then player cannot talk
  61.     TCHAR strPlayerName[MAX_PLAYER_NAME];   // Player name
  62. };
  63.  
  64.  
  65. IDirectPlay8Peer*  g_pDP                         = NULL;    // DirectPlay peer object
  66. CNetConnectWizard* g_pNetConnectWizard           = NULL;    // Connection wizard
  67. IDirectPlay8LobbiedApplication* g_pLobbiedApp    = NULL;    // DirectPlay lobbied app 
  68. BOOL               g_bWasLobbyLaunched           = FALSE;   // TRUE if lobby launched
  69. CNetVoice*         g_pNetVoice                   = NULL;    // DirectPlay voice helper class
  70. HINSTANCE          g_hInst                       = NULL;    // HINST of app
  71. HWND               g_hDlg                        = NULL;    // HWND of main dialog
  72. TCHAR              g_strAppName[256]             = TEXT("VoiceConnect");
  73. BOOL               g_bVoiceSessionInProgress     = FALSE;   // True if voice has been init'ed
  74. DPNID*             g_pPlayers                    = NULL;    // Array of DPNIDs
  75. DWORD              g_dwPlayersArraySize          = 0;       // Size of g_pPlayers
  76. HRESULT            g_hrDialog;                              // Exit code for app 
  77. TCHAR              g_strLocalPlayerName[MAX_PATH];          // Local player name
  78. TCHAR              g_strSessionName[MAX_PATH];              // Session name
  79. TCHAR              g_strPreferredProvider[MAX_PATH];        // Provider string
  80. BOOL               g_bHostPlayer;                           // TRUE if local player is host
  81. DPNID              g_LocalPlayerDPNID;                      // DPNID of local player
  82. GUID               g_guidDVSessionCT;                       // GUID for choosen voice compression
  83. DVCLIENTCONFIG     g_dvClientConfig;                        // Voice client config
  84.  
  85.  
  86.  
  87.  
  88. //-----------------------------------------------------------------------------
  89. // Function-prototypes
  90. //-----------------------------------------------------------------------------
  91. INT_PTR CALLBACK VoiceDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam );
  92. HRESULT          InitDirectPlay();
  93. HRESULT          OnInitDialog( HWND hDlg );
  94. HRESULT          DisplayPlayersInChat( HWND hDlg );
  95. HRESULT WINAPI   DirectPlayMessageHandler( LPVOID lpvUserContext, DWORD dwMessageType, LPVOID lpMessage );
  96. HRESULT WINAPI   DirectPlayLobbyMessageHandler( PVOID pvUserContext, DWORD dwMessageId, PVOID pMsgBuffer );
  97. HRESULT WINAPI   DirectPlayVoiceClientMessageHandler( PVOID pvUserContext, DWORD dwMessageId, PVOID pMsgBuffer );
  98. HRESULT WINAPI   DirectPlayVoiceServerMessageHandler( PVOID pvUserContext, DWORD dwMessageId, PVOID pMsgBuffer );
  99. void             SetPlayerTalking( APP_PLAYER_INFO *pPlayerInfo, BOOL bTalking );
  100. INT_PTR CALLBACK VoiceConfigDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam );
  101. HRESULT          VoiceConfigEnumCompressionCodecs( HWND hDlg );
  102. VOID             VoiceConfigDlgOnOK( HWND hDlg );
  103.  
  104.  
  105.  
  106.  
  107. //-----------------------------------------------------------------------------
  108. // Name: WinMain()
  109. // Desc: Entry point for the application.  Since we use a simple dialog for 
  110. //       user interaction we don't need to pump messages.
  111. //-----------------------------------------------------------------------------
  112. INT APIENTRY WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR pCmdLine, 
  113.                       INT nCmdShow )
  114. {
  115.     HRESULT hr;
  116.     HKEY    hDPlaySampleRegKey;
  117.     BOOL    bConnectSuccess = FALSE;
  118.  
  119.     g_hInst = hInst;
  120.     InitializeCriticalSection( &g_csPlayerContext );
  121.  
  122.     // Init player ID array 
  123.     g_dwPlayersArraySize = 10;
  124.     g_pPlayers = (DPNID*) malloc( sizeof(DPNID)*g_dwPlayersArraySize );
  125.  
  126.     // Read persistent state information from registry
  127.     RegCreateKeyEx( HKEY_CURRENT_USER, DPLAY_SAMPLE_KEY, 0, NULL,
  128.                     REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, 
  129.                     &hDPlaySampleRegKey, NULL );
  130.     DXUtil_ReadStringRegKey( hDPlaySampleRegKey, TEXT("Player Name"), 
  131.                              g_strLocalPlayerName, MAX_PATH, TEXT("TestPlayer") );
  132.     DXUtil_ReadStringRegKey( hDPlaySampleRegKey, TEXT("Session Name"), 
  133.                              g_strSessionName, MAX_PATH, TEXT("TestGame") );
  134.     DXUtil_ReadStringRegKey( hDPlaySampleRegKey, TEXT("Preferred Provider"), 
  135.                              g_strPreferredProvider, MAX_PATH, 
  136.                              TEXT("DirectPlay8 TCP/IP Service Provider") );
  137.  
  138.     InitCommonControls();
  139.  
  140.     // Init COM so we can use CoCreateInstance
  141.     CoInitializeEx( NULL, COINIT_MULTITHREADED );
  142.  
  143.     // Create helper class
  144.     g_pNetConnectWizard = new CNetConnectWizard( hInst, g_strAppName, &g_guidApp );
  145.     g_pNetVoice         = new CNetVoice( DirectPlayVoiceClientMessageHandler, DirectPlayVoiceServerMessageHandler );
  146.  
  147.     if( FAILED( hr = InitDirectPlay() ) )
  148.     {
  149.         DXTRACE_ERR( TEXT("InitDirectPlay"), hr );
  150.         MessageBox( NULL, TEXT("Failed initializing IDirectPlay8Peer. ")
  151.                     TEXT("The sample will now quit."),
  152.                     TEXT("DirectPlay Sample"), MB_OK | MB_ICONERROR );
  153.         return FALSE;
  154.     }
  155.  
  156.     // Check if we were launched from a lobby client
  157.     if( g_bWasLobbyLaunched && g_pNetConnectWizard->HaveConnectionSettingsFromLobby() )
  158.     {
  159.         // If were lobby launched then DPL_MSGID_CONNECT has already been
  160.         // handled, so we can just tell the wizard to connect to the lobby
  161.         // that has sent us a DPL_MSGID_CONNECT msg.
  162.         if( FAILED( hr = g_pNetConnectWizard->ConnectUsingLobbySettings() ) )
  163.         {
  164.             DXTRACE_ERR( TEXT("ConnectUsingLobbySettings"), hr );
  165.             MessageBox( NULL, TEXT("Failed to connect using lobby settings. ")
  166.                         TEXT("The sample will now quit."),
  167.                         TEXT("DirectPlay Sample"), MB_OK | MB_ICONERROR );
  168.  
  169.             bConnectSuccess = FALSE;
  170.         }
  171.         else
  172.         {
  173.             // Read information from g_pNetConnectWizard
  174.             _tcscpy( g_strLocalPlayerName, g_pNetConnectWizard->GetPlayerName() );
  175.             g_bHostPlayer = g_pNetConnectWizard->IsHostPlayer();
  176.  
  177.             bConnectSuccess = TRUE; 
  178.         }
  179.     }
  180.     else
  181.     {
  182.         // If not lobby launched, prompt the user about the network 
  183.         // connection and which session they would like to join or 
  184.         // if they want to create a new one.
  185.  
  186.         // Setup connection wizard
  187.         g_pNetConnectWizard->SetPlayerName( g_strLocalPlayerName );
  188.         g_pNetConnectWizard->SetSessionName( g_strSessionName );
  189.         g_pNetConnectWizard->SetPreferredProvider( g_strPreferredProvider );
  190.  
  191.         // Do the connection wizard
  192.         hr = g_pNetConnectWizard->DoConnectWizard( FALSE );        
  193.         if( FAILED( hr ) ) 
  194.         {
  195.             DXTRACE_ERR( TEXT("DoConnectWizard"), hr );
  196.             MessageBox( NULL, TEXT("Mutliplayer connect failed. ")
  197.                         TEXT("The sample will now quit."),
  198.                         TEXT("DirectPlay Sample"), MB_OK | MB_ICONERROR );
  199.             bConnectSuccess = FALSE;
  200.         } 
  201.         else if( hr == NCW_S_QUIT ) 
  202.         {
  203.             // The user canceled the mutliplayer connect, so quit 
  204.             bConnectSuccess = FALSE;
  205.         }
  206.         else
  207.         {
  208.             bConnectSuccess = TRUE; 
  209.  
  210.             // Read information from g_pNetConnectWizard
  211.             _tcscpy( g_strLocalPlayerName, g_pNetConnectWizard->GetPlayerName() );
  212.             _tcscpy( g_strSessionName, g_pNetConnectWizard->GetSessionName() );
  213.             _tcscpy( g_strPreferredProvider, g_pNetConnectWizard->GetPreferredProvider() );
  214.             g_bHostPlayer = g_pNetConnectWizard->IsHostPlayer();
  215.  
  216.             // Write information to the registry
  217.             DXUtil_WriteStringRegKey( hDPlaySampleRegKey, TEXT("Player Name"), g_strLocalPlayerName );
  218.             DXUtil_WriteStringRegKey( hDPlaySampleRegKey, TEXT("Session Name"), g_strSessionName );
  219.             DXUtil_WriteStringRegKey( hDPlaySampleRegKey, TEXT("Preferred Provider"), g_strPreferredProvider );
  220.         }
  221.     }
  222.  
  223.     if( bConnectSuccess )
  224.     {
  225.         // Set default DirectPlayVoice setup options
  226.         ZeroMemory( &g_dvClientConfig, sizeof(g_dvClientConfig) );
  227.         g_dvClientConfig.dwSize                 = sizeof(g_dvClientConfig);
  228.         g_dvClientConfig.dwFlags                = DVCLIENTCONFIG_AUTOVOICEACTIVATED |
  229.                                                   DVCLIENTCONFIG_AUTORECORDVOLUME;
  230.         g_dvClientConfig.lPlaybackVolume        = DVPLAYBACKVOLUME_DEFAULT;
  231.         g_dvClientConfig.dwBufferQuality        = DVBUFFERQUALITY_DEFAULT;
  232.         g_dvClientConfig.dwBufferAggressiveness = DVBUFFERAGGRESSIVENESS_DEFAULT;
  233.         g_dvClientConfig.dwThreshold          = DVTHRESHOLD_UNUSED;
  234.         g_dvClientConfig.lRecordVolume          = DVRECORDVOLUME_LAST;
  235.         g_dvClientConfig.dwNotifyPeriod         = 0;
  236.  
  237.         g_guidDVSessionCT                       = DPVCTGUID_DEFAULT;
  238.  
  239.         // Ask user to change g_dvClientConfig, g_guidDVSessionCT
  240.         DWORD dwResult = (DWORD)DialogBox( hInst, MAKEINTRESOURCE(IDD_VOICE_SETUP), 
  241.                                            NULL, (DLGPROC) VoiceConfigDlgProc );
  242.     }
  243.  
  244.     if( bConnectSuccess )
  245.     {
  246.         // App is now connected via DirectPlay, so start the game.  
  247.  
  248.         // For this sample, we just start a simple dialog box game.
  249.         g_hrDialog = S_OK;
  250.         DialogBox( hInst, MAKEINTRESOURCE(IDD_MAIN_GAME), NULL, (DLGPROC) VoiceDlgProc );
  251.  
  252.         if( FAILED( g_hrDialog ) )
  253.         {
  254.             if( g_hrDialog == DPNERR_CONNECTIONLOST )
  255.             {
  256.                 MessageBox( NULL, TEXT("The DirectPlay session was lost. ")
  257.                             TEXT("The sample will now quit."),
  258.                             TEXT("DirectPlay Sample"), MB_OK | MB_ICONERROR );
  259.             }
  260.             else
  261.             {
  262.                 DXTRACE_ERR( TEXT("DialogBox"), hr );
  263.                 MessageBox( NULL, TEXT("An error occured during the game. ")
  264.                             TEXT("The sample will now quit."),
  265.                             TEXT("DirectPlay Sample"), MB_OK | MB_ICONERROR );
  266.             }
  267.         }
  268.     }
  269.  
  270.     // Cleanup player ID array 
  271.     free( g_pPlayers );
  272.  
  273.     // Disconnect from the DirectPlayVoice session, 
  274.     // and destory it if we are the host player.
  275.     SAFE_DELETE( g_pNetVoice ); 
  276.  
  277.     // Cleanup DirectPlay and helper classes
  278.     g_pNetConnectWizard->Shutdown();
  279.  
  280.     if( g_pDP )
  281.     {
  282.         g_pDP->Close(0);
  283.         SAFE_RELEASE( g_pDP );
  284.     }
  285.  
  286.     if( g_pLobbiedApp )
  287.     {
  288.         g_pLobbiedApp->Close( 0 );
  289.         SAFE_RELEASE( g_pLobbiedApp );
  290.     }    
  291.  
  292.     // Don't delete the wizard until we know that 
  293.     // DirectPlay is out of its message handlers.
  294.     // This will be true after Close() has been called. 
  295.     SAFE_DELETE( g_pNetConnectWizard );
  296.  
  297.     RegCloseKey( hDPlaySampleRegKey );
  298.     DeleteCriticalSection( &g_csPlayerContext );
  299.     CoUninitialize();
  300.  
  301.     return TRUE;
  302. }
  303.  
  304.  
  305.  
  306.  
  307. //-----------------------------------------------------------------------------
  308. // Name: InitDirectPlay()
  309. // Desc: 
  310. //-----------------------------------------------------------------------------
  311. HRESULT InitDirectPlay()
  312. {
  313.     DPNHANDLE hLobbyLaunchedConnection = NULL;
  314.     HRESULT hr;
  315.  
  316.     // Create IDirectPlay8Peer
  317.     if( FAILED( hr = CoCreateInstance( CLSID_DirectPlay8Peer, NULL, 
  318.                                        CLSCTX_INPROC_SERVER,
  319.                                        IID_IDirectPlay8Peer, 
  320.                                        (LPVOID*) &g_pDP ) ) )
  321.         return DXTRACE_ERR( TEXT("CoCreateInstance"), hr );
  322.  
  323.     // Create IDirectPlay8LobbiedApplication
  324.     if( FAILED( hr = CoCreateInstance( CLSID_DirectPlay8LobbiedApplication, NULL, 
  325.                                        CLSCTX_INPROC_SERVER,
  326.                                        IID_IDirectPlay8LobbiedApplication, 
  327.                                        (LPVOID*) &g_pLobbiedApp ) ) )
  328.         return DXTRACE_ERR( TEXT("CoCreateInstance"), hr );
  329.  
  330.     // Init the helper class, now that g_pDP and g_pLobbiedApp are valid
  331.     g_pNetConnectWizard->Init( g_pDP, g_pLobbiedApp );
  332.  
  333.     // Init IDirectPlay8Peer
  334.     if( FAILED( hr = g_pDP->Initialize( NULL, DirectPlayMessageHandler, 0 ) ) )
  335.         return DXTRACE_ERR( TEXT("Initialize"), hr );
  336.  
  337.     // Init IDirectPlay8LobbiedApplication.  Before this Initialize() returns 
  338.     // a DPL_MSGID_CONNECT msg may come in to the DirectPlayLobbyMessageHandler 
  339.     // so be prepared ahead of time.
  340.     if( FAILED( hr = g_pLobbiedApp->Initialize( NULL, DirectPlayLobbyMessageHandler, 
  341.                                                 &hLobbyLaunchedConnection, 0 ) ) )
  342.         return DXTRACE_ERR( TEXT("Initialize"), hr );
  343.  
  344.     // IDirectPlay8LobbiedApplication::Initialize returns a handle to a connnection
  345.     // if we have been lobby launced.  Initialize is guanteeded to return after 
  346.     // the DPL_MSGID_CONNECT msg has been processed.  So unless a we are expected 
  347.     // multiple lobby connections, we do not need to remember the lobby connection
  348.     // handle since it will be recorded upon the DPL_MSGID_CONNECT msg.
  349.     g_bWasLobbyLaunched = ( hLobbyLaunchedConnection != NULL );
  350.  
  351.     return S_OK;
  352. }
  353.  
  354.  
  355.  
  356.  
  357. //-----------------------------------------------------------------------------
  358. // Name: VoiceDlgProc()
  359. // Desc: Handles dialog messages
  360. //-----------------------------------------------------------------------------
  361. INT_PTR CALLBACK VoiceDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam )
  362. {
  363.     switch( msg ) 
  364.     {
  365.         case WM_INITDIALOG:
  366.             {
  367.                 g_hDlg = hDlg;
  368.  
  369.                 if( FAILED( g_hrDialog = g_pNetVoice->Init( hDlg, g_bHostPlayer, TRUE,
  370.                                                             g_pDP, DVSESSIONTYPE_PEER, 
  371.                                                             &g_guidDVSessionCT, &g_dvClientConfig ) ) )
  372.                 {
  373.                     if( g_hrDialog == DVERR_USERBACK )
  374.                     {
  375.                         MessageBox( hDlg, TEXT("The user backed out of the wizard.  ")
  376.                                     TEXT("This simple sample does not handle this case, so ")
  377.                                     TEXT("the sample will quit."), TEXT("DirectPlay Sample"), MB_OK );
  378.                         g_hrDialog = S_OK;
  379.                     }
  380.  
  381.                     if( g_hrDialog == DVERR_USERCANCEL )
  382.                     {
  383.                         MessageBox( hDlg, TEXT("The user canceled the wizard. ")
  384.                                     TEXT("This simple sample does not handle this case, so ")
  385.                                     TEXT("the sample will quit."), TEXT("DirectPlay Sample"), MB_OK );
  386.                         g_hrDialog = S_OK;
  387.                     }
  388.  
  389.                     if( FAILED(g_hrDialog) ) 
  390.                         DXTRACE_ERR( TEXT("Init"), g_hrDialog );
  391.  
  392.                     EndDialog( hDlg, 0 );
  393.                     break;
  394.                 }
  395.  
  396.                 if( g_pNetVoice->IsHalfDuplex() ) 
  397.                 {
  398.                     MessageBox( hDlg, TEXT("You are running in half duplex mode. ")
  399.                                 TEXT("In half duplex mode no recording takes place."), 
  400.                                 TEXT("DirectPlay Sample"), MB_OK );
  401.                 }
  402.  
  403.                 g_bVoiceSessionInProgress = TRUE;
  404.  
  405.                 if( FAILED( g_hrDialog = OnInitDialog( hDlg ) ) )
  406.                 {
  407.                     DXTRACE_ERR( TEXT("OnInitDialog"), g_hrDialog );
  408.                     EndDialog( hDlg, 0 );
  409.                     break;
  410.                 }
  411.             }
  412.             break;
  413.  
  414.         case WM_COMMAND:
  415.             switch( LOWORD(wParam) )
  416.             {
  417.                 case IDC_SETUP:
  418.                     {
  419.                         // Ask the user for DirectPlayVoice setup params
  420.                         DWORD dwResult = (DWORD)DialogBox( g_hInst, 
  421.                                                            MAKEINTRESOURCE(IDD_VOICE_SETUP), 
  422.                                                            hDlg, (DLGPROC) VoiceConfigDlgProc );
  423.                         if( dwResult != IDCANCEL )
  424.                             g_pNetVoice->ChangeVoiceClientSettings( &g_dvClientConfig );
  425.                     }
  426.                     return TRUE;
  427.  
  428.                 case IDCANCEL:
  429.                     g_hrDialog = S_OK;
  430.                     EndDialog( hDlg, 0 );
  431.                     return TRUE;
  432.             }
  433.             break;
  434.  
  435.         case WM_APP_DISPLAY_PLAYERS:
  436.         {
  437.             DisplayPlayersInChat( hDlg );
  438.             break;
  439.         }
  440.  
  441.         case WM_TIMER:
  442.         {
  443.             DWORD            dwNumPlayers;
  444.             DWORD            iIndex;
  445.             LVITEM           lvItem;
  446.             APP_PLAYER_INFO* pPlayerInfo = NULL;
  447.             HWND             hListView = GetDlgItem( hDlg, IDC_PEOPLE_LIST );
  448.  
  449.             dwNumPlayers = ListView_GetItemCount( hListView );
  450.  
  451.             // Now that they are added and the listview sorted them by name,
  452.             // run through them all caching the listview index with its dpnid
  453.             for( iIndex = 0; iIndex < dwNumPlayers; iIndex++ )
  454.             {
  455.                 HRESULT hr;
  456.                 APP_PLAYER_INFO* pPlayerInfo = NULL;
  457.                 DPNID dpnidPlayer;
  458.  
  459.                 lvItem.mask  = LVIF_PARAM;
  460.                 lvItem.iItem = iIndex;
  461.                 ListView_GetItem( hListView, &lvItem );
  462.  
  463.                 dpnidPlayer = (DPNID) lvItem.lParam;
  464.  
  465.                 PLAYER_LOCK(); // enter player context CS
  466.  
  467.                 // Get the player context accosicated with this DPNID
  468.                 hr = g_pDP->GetPlayerContext( dpnidPlayer, 
  469.                                               (LPVOID* const) &pPlayerInfo,
  470.                                               0);
  471.  
  472.  
  473.                 PLAYER_ADDREF( pPlayerInfo ); // addref player, since we are using it now
  474.                 PLAYER_UNLOCK(); // leave player context CS
  475.  
  476.                 if( FAILED(hr) || pPlayerInfo == NULL )
  477.                 {
  478.                     // The player who sent this may have gone away before this 
  479.                     // message was handled, so just ignore it
  480.                     continue;
  481.                 }
  482.  
  483.                 TCHAR strStatus[255];
  484.  
  485.                 if( pPlayerInfo->bHalfDuplex )
  486.                 {
  487.                     _tcscpy( strStatus, TEXT("Can't talk") );
  488.                 }
  489.                 else
  490.                 {
  491.                     if( pPlayerInfo->bTalking )
  492.                         _tcscpy( strStatus, TEXT("Talking") );
  493.                     else
  494.                         _tcscpy( strStatus, TEXT("Silent") );
  495.                 }
  496.  
  497.                 lvItem.iItem      = iIndex;
  498.                 lvItem.iSubItem   = 1;
  499.                 lvItem.mask       = LVIF_TEXT;
  500.                 lvItem.pszText    = strStatus;
  501.  
  502.                 PLAYER_LOCK();
  503.                 PLAYER_RELEASE( pPlayerInfo );  // Release player and cleanup if needed
  504.                 PLAYER_UNLOCK();
  505.  
  506.                 SendMessage( hListView, LVM_SETITEM, 0, (LPARAM) &lvItem );
  507.             }
  508.             break;
  509.         }
  510.     }
  511.  
  512.     return FALSE; // Didn't handle message
  513. }
  514.  
  515.  
  516.  
  517.  
  518. //-----------------------------------------------------------------------------
  519. // Name: OnInitDialog()
  520. // Desc: Inits the dialog 
  521. //-----------------------------------------------------------------------------
  522. HRESULT OnInitDialog( HWND hDlg )
  523. {
  524.     LVCOLUMN column;
  525.     RECT     rctListView;
  526.     TCHAR    strHeader[255];
  527.     DWORD    dwVertScrollBar;
  528.     DWORD    dwListViewWidth;
  529.  
  530.     // Load and set the icon
  531.     HICON hIcon = LoadIcon( g_hInst, MAKEINTRESOURCE( IDI_MAIN ) );
  532.     SendMessage( hDlg, WM_SETICON, ICON_BIG,   (LPARAM) hIcon );  // Set big icon
  533.     SendMessage( hDlg, WM_SETICON, ICON_SMALL, (LPARAM) hIcon );  // Set small icon
  534.  
  535.     if( g_bHostPlayer )
  536.         SetWindowText( hDlg, TEXT("VoiceConnect (Session Host)") );
  537.     else
  538.         SetWindowText( hDlg, TEXT("VoiceConnect (Session Client)") );
  539.  
  540.     // Setup the listview
  541.     HWND hListView = GetDlgItem( hDlg, IDC_PEOPLE_LIST );
  542.     dwVertScrollBar = GetSystemMetrics( SM_CXVSCROLL );  
  543.     GetClientRect( hListView, &rctListView );
  544.     dwListViewWidth = rctListView.right - dwVertScrollBar;
  545.     column.mask     = LVCF_FMT | LVCF_SUBITEM | LVCF_TEXT | LVCF_WIDTH;
  546.     column.fmt      = LVCFMT_LEFT;
  547.     column.iSubItem = -1;
  548.  
  549.     // Insert the Name column
  550.     _tcscpy( strHeader, TEXT("Name") );
  551.     column.cx         = dwListViewWidth * 5 / 10;
  552.     column.pszText    = strHeader;
  553.     column.cchTextMax = _tcslen( strHeader );
  554.     ListView_InsertColumn( hListView, 0, &column );
  555.  
  556.     // Insert the Status column
  557.     _tcscpy( strHeader, TEXT("Status") );
  558.     column.cx         = dwListViewWidth * 5 / 10;
  559.     column.pszText    = strHeader;
  560.     column.cchTextMax = _tcslen( strHeader );
  561.     ListView_InsertColumn( hListView, 1, &column );
  562.  
  563.     // Update the listbox 
  564.     PostMessage( g_hDlg, WM_APP_DISPLAY_PLAYERS, 0, 0 );
  565.  
  566.     // Make a timer to update the listbox 
  567.     // 'Status' column every so often 
  568.     SetTimer( hDlg, 0, 250, NULL );
  569.  
  570.     return S_OK;
  571. }
  572.  
  573.  
  574.  
  575.  
  576. //-----------------------------------------------------------------------------
  577. // Name: DisplayPlayersInChat()
  578. // Desc: Displays the active players in the listview
  579. //-----------------------------------------------------------------------------
  580. HRESULT DisplayPlayersInChat( HWND hDlg )
  581. {
  582.     if( hDlg == NULL )
  583.         return S_OK;
  584.  
  585.     HRESULT hr;
  586.     LVITEM  lvItem;
  587.     HWND    hListView = GetDlgItem( hDlg, IDC_PEOPLE_LIST );
  588.     TCHAR   strStatus[32];
  589.     TCHAR   strNumberPlayers[32];
  590.     DWORD   dwNumPlayers;
  591.     APP_PLAYER_INFO* pPlayerInfo = NULL;
  592.  
  593.     // Remove all the players and re-add them in the player enum callback
  594.     ListView_DeleteAllItems( hListView );
  595.  
  596.     do
  597.     {
  598.         // Enum all players in the player ID array
  599.         dwNumPlayers = g_dwPlayersArraySize;
  600.         hr = g_pDP->EnumPlayersAndGroups( g_pPlayers, &dwNumPlayers, DPNENUM_PLAYERS );
  601.         if( SUCCEEDED(hr) )
  602.             break;
  603.  
  604.         if( hr == DPNERR_BUFFERTOOSMALL )
  605.         {
  606.             // Resize player pointer array     
  607.             g_dwPlayersArraySize += 10;
  608.             g_pPlayers   = (DPNID*) realloc( g_pPlayers, sizeof(DPNID)*g_dwPlayersArraySize );
  609.         }                
  610.     }         
  611.     while( hr == DPNERR_BUFFERTOOSMALL );
  612.  
  613.     if( FAILED(hr) )                    
  614.         return DXTRACE_ERR( TEXT("EnumPlayersAndGroups"), hr );
  615.  
  616.     for( DWORD i = 0; i<dwNumPlayers; i++ )
  617.     {
  618.         PLAYER_LOCK(); // enter player context CS
  619.  
  620.         // Get the player context accosicated with this DPNID
  621.         hr = g_pDP->GetPlayerContext( g_pPlayers[i], 
  622.                                       (LPVOID* const) &pPlayerInfo,
  623.                                       0);
  624.  
  625.         PLAYER_ADDREF( pPlayerInfo ); // addref player, since we are using it now
  626.         PLAYER_UNLOCK(); // leave player context CS
  627.  
  628.         if( FAILED(hr) || pPlayerInfo == NULL )
  629.         {
  630.             // The player who sent this may have gone away before this 
  631.             // message was handled, so just ignore it
  632.             continue;
  633.         }
  634.  
  635.         ZeroMemory( &lvItem, sizeof(lvItem) );
  636.  
  637.         // Add the item, saving the player's name and dpnid in the listview
  638.         lvItem.mask       = LVIF_TEXT | LVIF_PARAM;
  639.         lvItem.iItem      = 0;
  640.         lvItem.iSubItem   = 0;
  641.         lvItem.pszText    = pPlayerInfo->strPlayerName;
  642.         lvItem.lParam     = g_pPlayers[i];
  643.         lvItem.cchTextMax = _tcslen( pPlayerInfo->strPlayerName );
  644.         int nIndex = ListView_InsertItem( hListView, &lvItem );
  645.  
  646.         if( pPlayerInfo->bHalfDuplex )
  647.         {
  648.             _tcscpy( strStatus, TEXT("Can't talk") );
  649.         }
  650.         else
  651.         {
  652.             if( pPlayerInfo->bTalking )
  653.                 _tcscpy( strStatus, TEXT("Talking") );
  654.             else
  655.                 _tcscpy( strStatus, TEXT("Silent") );
  656.         }
  657.  
  658.         PLAYER_LOCK();
  659.         PLAYER_RELEASE( pPlayerInfo );  // Release player and cleanup if needed
  660.         PLAYER_UNLOCK();
  661.  
  662.         // Start the player's status off as silent.  
  663.         lvItem.mask       = LVIF_TEXT;
  664.         lvItem.iItem      = nIndex;
  665.         lvItem.iSubItem   = 1;
  666.         lvItem.pszText    = strStatus;
  667.         lvItem.cchTextMax = _tcslen( strStatus );
  668.         ListView_SetItem( hListView, &lvItem );
  669.     }
  670.  
  671.     wsprintf( strNumberPlayers, TEXT("%d"), dwNumPlayers );
  672.     SetDlgItemText( hDlg, IDC_NUM_PLAYERS, strNumberPlayers );
  673.  
  674.     return S_OK;
  675. }
  676.  
  677.  
  678.  
  679.  
  680. //-----------------------------------------------------------------------------
  681. // Name: DirectPlayMessageHandler
  682. // Desc: Handler for DirectPlay messages.  This function is called by
  683. //       the DirectPlay message handler pool of threads, so be care of thread
  684. //       synchronization problems with shared memory
  685. //-----------------------------------------------------------------------------
  686. HRESULT WINAPI DirectPlayMessageHandler( PVOID pvUserContext, 
  687.                                          DWORD dwMessageId, 
  688.                                          PVOID pMsgBuffer )
  689. {
  690.     // Try not to stay in this message handler for too long, otherwise
  691.     // there will be a backlog of data.  The best solution is to 
  692.     // queue data as it comes in, and then handle it on other threads.
  693.     
  694.     // This function is called by the DirectPlay message handler pool of 
  695.     // threads, so be care of thread synchronization problems with shared memory
  696.  
  697.     switch( dwMessageId )
  698.     {
  699.         case DPN_MSGID_CREATE_PLAYER:
  700.         {
  701.             HRESULT hr;
  702.             PDPNMSG_CREATE_PLAYER pCreatePlayerMsg;
  703.             pCreatePlayerMsg = (PDPNMSG_CREATE_PLAYER)pMsgBuffer;
  704.  
  705.             // Get the peer info and extract its name
  706.             DWORD dwSize = 0;
  707.             DPN_PLAYER_INFO* pdpPlayerInfo = NULL;
  708.             hr = g_pDP->GetPeerInfo( pCreatePlayerMsg->dpnidPlayer, pdpPlayerInfo, &dwSize, 0 );
  709.             if( FAILED(hr) && hr != DPNERR_BUFFERTOOSMALL )
  710.                 return DXTRACE_ERR( TEXT("GetPeerInfo"), hr );
  711.             pdpPlayerInfo = (DPN_PLAYER_INFO*) new BYTE[ dwSize ];
  712.             ZeroMemory( pdpPlayerInfo, dwSize );
  713.             pdpPlayerInfo->dwSize = sizeof(DPN_PLAYER_INFO);
  714.             hr = g_pDP->GetPeerInfo( pCreatePlayerMsg->dpnidPlayer, pdpPlayerInfo, &dwSize, 0 );
  715.             if( FAILED(hr) )
  716.                 return DXTRACE_ERR( TEXT("GetPeerInfo"), hr );
  717.  
  718.             if( (pdpPlayerInfo->dwPlayerFlags & DPNPLAYER_LOCAL) != 0 )
  719.                 g_LocalPlayerDPNID = pCreatePlayerMsg->dpnidPlayer;
  720.  
  721.             // Create a new and fill in a APP_PLAYER_INFO
  722.             APP_PLAYER_INFO* pPlayerInfo = new APP_PLAYER_INFO;
  723.             ZeroMemory( pPlayerInfo, sizeof(APP_PLAYER_INFO) ); 
  724.             pPlayerInfo->lRefCount   = 1;
  725.             pPlayerInfo->dpnidPlayer = pCreatePlayerMsg->dpnidPlayer;
  726.  
  727.             // This stores a extra ANSI copy of the player name for 
  728.             // easier access.  This will be redundent copy since DPlay 
  729.             // also keeps a copy of the player name in GetPeerInfo()
  730.             DXUtil_ConvertWideStringToGeneric( pPlayerInfo->strPlayerName, 
  731.                                                pdpPlayerInfo->pwszName, MAX_PLAYER_NAME );
  732.  
  733.             SAFE_DELETE_ARRAY( pdpPlayerInfo );
  734.  
  735.             // Tell DirectPlay to store this pPlayerInfo 
  736.             // pointer in the pvPlayerContext.
  737.             pCreatePlayerMsg->pvPlayerContext = pPlayerInfo;
  738.  
  739.             // Post a message to the dialog thread to update the 
  740.             // UI.  This keeps the DirectPlay message handler 
  741.             // from blocking
  742.             if( g_hDlg != NULL )
  743.                 PostMessage( g_hDlg, WM_APP_DISPLAY_PLAYERS, 0, 0 );
  744.             break;
  745.         }
  746.  
  747.         case DPN_MSGID_DESTROY_PLAYER:
  748.         {
  749.             PDPNMSG_DESTROY_PLAYER pDestroyPlayerMsg;
  750.             pDestroyPlayerMsg = (PDPNMSG_DESTROY_PLAYER)pMsgBuffer;
  751.             APP_PLAYER_INFO* pPlayerInfo = (APP_PLAYER_INFO*) pDestroyPlayerMsg->pvPlayerContext;
  752.  
  753.             PLAYER_LOCK();                  // enter player context CS
  754.             PLAYER_RELEASE( pPlayerInfo );  // Release player and cleanup if needed
  755.             PLAYER_UNLOCK();                // leave player context CS
  756.  
  757.             // Post a message to the dialog thread to update the 
  758.             // UI.  This keeps the DirectPlay message handler 
  759.             // from blocking
  760.             if( g_hDlg != NULL )
  761.                 PostMessage( g_hDlg, WM_APP_DISPLAY_PLAYERS, 0, 0 );
  762.             break;
  763.         }
  764.  
  765.         case DPN_MSGID_TERMINATE_SESSION:
  766.         {
  767.             PDPNMSG_TERMINATE_SESSION pTerminateSessionMsg;
  768.             pTerminateSessionMsg = (PDPNMSG_TERMINATE_SESSION)pMsgBuffer;
  769.  
  770.             g_hrDialog = DPNERR_CONNECTIONLOST;
  771.             EndDialog( g_hDlg, 0 );
  772.             break;
  773.         }
  774.     }
  775.  
  776.     // Make sure the DirectPlay MessageHandler calls the CNetConnectWizard handler, 
  777.     // so it can be informed of messages such as DPN_MSGID_ENUM_HOSTS_RESPONSE.
  778.     if( g_pNetConnectWizard )
  779.         return g_pNetConnectWizard->MessageHandler( pvUserContext, dwMessageId, pMsgBuffer );
  780.     
  781.     return S_OK;
  782. }
  783.  
  784.  
  785.  
  786.  
  787. //-----------------------------------------------------------------------------
  788. // Name: DirectPlayLobbyMessageHandler
  789. // Desc: Handler for DirectPlay lobby messages.  This function is called by
  790. //       the DirectPlay lobby message handler pool of threads, so be careful of 
  791. //       thread synchronization problems with shared memory
  792. //-----------------------------------------------------------------------------
  793. HRESULT WINAPI DirectPlayLobbyMessageHandler( PVOID pvUserContext, 
  794.                                               DWORD dwMessageId, 
  795.                                               PVOID pMsgBuffer )
  796. {
  797.     switch( dwMessageId )
  798.     {
  799.         case DPL_MSGID_CONNECT:
  800.         {
  801.             PDPL_MESSAGE_CONNECT pConnectMsg;
  802.             pConnectMsg = (PDPL_MESSAGE_CONNECT)pMsgBuffer;
  803.  
  804.             // The CNetConnectWizard will handle this message for us,
  805.             // so there is nothing we need to do here for this simple
  806.             // sample.
  807.             break;
  808.         }
  809.  
  810.         case DPL_MSGID_DISCONNECT:
  811.         {
  812.             PDPL_MESSAGE_DISCONNECT pDisconnectMsg;
  813.             pDisconnectMsg = (PDPL_MESSAGE_DISCONNECT)pMsgBuffer;
  814.  
  815.             // We should free any data associated with the lobby 
  816.             // client here, but there is none.
  817.             break;
  818.         }
  819.  
  820.         case DPL_MSGID_RECEIVE:
  821.         {
  822.             PDPL_MESSAGE_RECEIVE pReceiveMsg;
  823.             pReceiveMsg = (PDPL_MESSAGE_RECEIVE)pMsgBuffer;
  824.  
  825.             // The lobby client sent us data.  This sample doesn't
  826.             // expected data from the client, but it is useful 
  827.             // for more complex apps.
  828.             break;
  829.         }
  830.  
  831.         case DPL_MSGID_CONNECTION_SETTINGS:
  832.         {
  833.             PDPL_MESSAGE_CONNECTION_SETTINGS pConnectionStatusMsg;
  834.             pConnectionStatusMsg = (PDPL_MESSAGE_CONNECTION_SETTINGS)pMsgBuffer;
  835.  
  836.             // The lobby client has changed the connection settings.  
  837.             // This simple sample doesn't handle this, but more complex apps may
  838.             // want to.
  839.             break;
  840.         }
  841.     }
  842.  
  843.     // Make sure the DirectPlay MessageHandler calls the CNetConnectWizard handler, 
  844.     // so the wizard can be informed of lobby messages such as DPL_MSGID_CONNECT
  845.     if( g_pNetConnectWizard )
  846.         return g_pNetConnectWizard->LobbyMessageHandler( pvUserContext, dwMessageId, 
  847.                                                          pMsgBuffer );
  848.     
  849.     return S_OK;
  850. }
  851.  
  852.  
  853.  
  854.  
  855. //-----------------------------------------------------------------------------
  856. // Name: DirectPlayVoiceServerMessageHandler()
  857. // Desc: The callback for DirectPlayVoice server messages.  
  858. //-----------------------------------------------------------------------------
  859. HRESULT CALLBACK DirectPlayVoiceServerMessageHandler( LPVOID lpvUserContext, DWORD dwMessageType,
  860.                                                       LPVOID lpMessage )
  861. {
  862.     // This simple sample doesn't respond to any server messages
  863.     return S_OK;
  864. }
  865.  
  866.  
  867.  
  868.  
  869. //-----------------------------------------------------------------------------
  870. // Name: DirectPlayVoiceClientMessageHandler()
  871. // Desc: The callback for DirectPlayVoice client messages.  
  872. //       This handles client messages and updates the UI the whenever a client 
  873. //       starts or stops talking.  
  874. //-----------------------------------------------------------------------------
  875. HRESULT CALLBACK DirectPlayVoiceClientMessageHandler( LPVOID lpvUserContext, DWORD dwMessageType,
  876.                                                       LPVOID lpMessage )
  877. {
  878.     // Try not to stay in this message handler for too long, otherwise
  879.     // there will be a backlog of data.  The best solution is to 
  880.     // queue data as it comes in, and then handle it on other threads.
  881.     
  882.     // This function is called by the DirectPlay message handler pool of 
  883.     // threads, so be care of thread synchronization problems with shared memory
  884.     HRESULT hr;
  885.     HWND hDlg = (HWND) lpvUserContext;
  886.  
  887.     switch( dwMessageType )
  888.     {
  889.         case DVMSGID_CREATEVOICEPLAYER:
  890.             {
  891.                 DVMSG_CREATEVOICEPLAYER* pCreateVoicePlayerMsg = (DVMSG_CREATEVOICEPLAYER*) lpMessage;
  892.                 APP_PLAYER_INFO* pPlayerInfo = NULL;
  893.  
  894.                 PLAYER_LOCK(); // enter player context CS
  895.  
  896.                 // Get the player context accosicated with this DPNID
  897.                 hr = g_pDP->GetPlayerContext( pCreateVoicePlayerMsg->dvidPlayer, 
  898.                                               (LPVOID* const) &pPlayerInfo,
  899.                                               0);
  900.  
  901.                 if( FAILED(hr) || pPlayerInfo == NULL )
  902.                 {
  903.                     // The player who sent this may have gone away before this 
  904.                     // message was handled, so just ignore it
  905.                     PLAYER_UNLOCK();
  906.                     break;
  907.                 }
  908.  
  909.                 PLAYER_ADDREF( pPlayerInfo ); // addref player, to be used by the voice layer
  910.                 PLAYER_UNLOCK(); // leave player context CS
  911.  
  912.                 pPlayerInfo->bHalfDuplex = ((pCreateVoicePlayerMsg->dwFlags & DVPLAYERCAPS_HALFDUPLEX) != 0);
  913.  
  914.                 // Set voice context value
  915.                 pCreateVoicePlayerMsg->pvPlayerContext = pPlayerInfo;
  916.  
  917.                 // Post a message to the dialog thread to update the 
  918.                 // UI.  This keeps the DirectPlay message handler 
  919.                 // from blocking
  920.                 if( g_hDlg != NULL )
  921.                     PostMessage( g_hDlg, WM_APP_DISPLAY_PLAYERS, 0, 0 );
  922.  
  923.                 // We're leaving the extra reference, voice will own that reference
  924.             }
  925.             break;
  926.  
  927.         case DVMSGID_DELETEVOICEPLAYER:
  928.         {
  929.             DVMSG_DELETEVOICEPLAYER* pMsg = (DVMSG_DELETEVOICEPLAYER*) lpMessage;
  930.             APP_PLAYER_INFO* pPlayerInfo = (APP_PLAYER_INFO*) pMsg->pvPlayerContext;
  931.  
  932.             // Don't update the dlg if this message is for the local 
  933.             // client since the dlg will be gone.
  934.             if( pMsg->dvidPlayer != g_LocalPlayerDPNID )
  935.             {
  936.                 // Post a message to the dialog thread to update the 
  937.                 // UI.  This keeps the DirectPlay message handler 
  938.                 // from blocking
  939.                 if( hDlg != NULL )
  940.                     PostMessage( hDlg, WM_APP_DISPLAY_PLAYERS, 0, 0 );
  941.             }
  942.  
  943.             // Release our extra reference on the player info that we have for the voice
  944.             // context value.  
  945.             //
  946.             PLAYER_LOCK();
  947.             PLAYER_RELEASE( pPlayerInfo );  
  948.             PLAYER_UNLOCK();
  949.             break;
  950.         }            
  951.  
  952.  
  953.         case DVMSGID_SESSIONLOST:
  954.             g_hrDialog = DPNERR_CONNECTIONLOST;
  955.             EndDialog( hDlg, 0 );
  956.             break;
  957.  
  958.         case DVMSGID_HOSTMIGRATED:
  959.         {
  960.             DVMSG_HOSTMIGRATED* pMsg = (DVMSG_HOSTMIGRATED*) lpMessage;
  961.  
  962.             if( pMsg->pdvServerInterface != NULL )
  963.             {           
  964.                 // If we keep the pMsg->pdvServerInterface pointer around, then
  965.                 // we must AddRef() it.  The CNetVoice::HostMigrate() automatically
  966.                 // does this for us.
  967.                 g_pNetVoice->HostMigrate( pMsg->pdvServerInterface );
  968.  
  969.                 g_bHostPlayer = TRUE;
  970.                 SetWindowText( hDlg, TEXT("VoiceConnect (Session Host)") );
  971.             }
  972.             break;
  973.         }
  974.  
  975.         case DVMSGID_GAINFOCUS:
  976.         case DVMSGID_LOSTFOCUS:
  977.         {
  978.             TCHAR strWindowName[MAX_PATH];
  979.             wsprintf( strWindowName, TEXT("%s%s%s"), g_strAppName,
  980.                 (g_bHostPlayer)                      ? TEXT(" (Session Host)") : TEXT(""),
  981.                 (dwMessageType == DVMSGID_LOSTFOCUS) ? TEXT(" (Focus Lost)") : TEXT("") );
  982.  
  983.             SetWindowText( hDlg, strWindowName );
  984.             break;
  985.         }
  986.  
  987.         case DVMSGID_RECORDSTART:             
  988.         { 
  989.             DVMSG_RECORDSTART* pMsg = (DVMSG_RECORDSTART*) lpMessage;
  990.             SetPlayerTalking( (APP_PLAYER_INFO*) pMsg->pvLocalPlayerContext, TRUE );
  991.             break;
  992.         }
  993.         case DVMSGID_RECORDSTOP:             
  994.         {
  995.             DVMSG_RECORDSTOP* pMsg = (DVMSG_RECORDSTOP*) lpMessage;
  996.             SetPlayerTalking( (APP_PLAYER_INFO*) pMsg->pvLocalPlayerContext, FALSE );
  997.             break;
  998.         }
  999.         case DVMSGID_PLAYERVOICESTART:
  1000.         {
  1001.             DVMSG_PLAYERVOICESTART* pMsg = (DVMSG_PLAYERVOICESTART*) lpMessage;
  1002.             SetPlayerTalking( (APP_PLAYER_INFO*) pMsg->pvPlayerContext, TRUE );
  1003.             break;
  1004.         }
  1005.  
  1006.         case DVMSGID_PLAYERVOICESTOP:
  1007.         {
  1008.             DVMSG_PLAYERVOICESTOP* pMsg = (DVMSG_PLAYERVOICESTOP*) lpMessage;
  1009.             SetPlayerTalking( (APP_PLAYER_INFO*) pMsg->pvPlayerContext, FALSE );            
  1010.             break;
  1011.         }
  1012.     }
  1013.  
  1014.     return S_OK;
  1015. }
  1016.  
  1017.  
  1018.  
  1019.  
  1020. //-----------------------------------------------------------------------------
  1021. // Name: SetPlayerTalking()
  1022. // Desc: Set player talking flag
  1023. //-----------------------------------------------------------------------------
  1024. void SetPlayerTalking( APP_PLAYER_INFO* pPlayerInfo, BOOL bTalking )
  1025. {
  1026.     if( pPlayerInfo )
  1027.         pPlayerInfo->bTalking = bTalking;     
  1028. }
  1029.  
  1030.  
  1031.  
  1032.  
  1033. //-----------------------------------------------------------------------------
  1034. // Name: VoiceConfigDlgProc()
  1035. // Desc: Prompt the user for DirectPlayVoice setup options
  1036. //-----------------------------------------------------------------------------
  1037. INT_PTR CALLBACK VoiceConfigDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam )
  1038. {
  1039.     DWORD dwSliderPos;
  1040.  
  1041.     switch( msg ) 
  1042.     {
  1043.         case WM_INITDIALOG:
  1044.             // Set the range on the sliders
  1045.             SendDlgItemMessage( hDlg, IDC_PLAYBACK_SLIDER,       TBM_SETRANGE, FALSE, MAKELONG( 0, 100 ) );
  1046.             SendDlgItemMessage( hDlg, IDC_RECORD_SLIDER,         TBM_SETRANGE, FALSE, MAKELONG( 0, 100 ) );
  1047.             SendDlgItemMessage( hDlg, IDC_QUALITY_SLIDER,        TBM_SETRANGE, FALSE, MAKELONG( DVBUFFERQUALITY_MIN, DVBUFFERQUALITY_MAX ) );
  1048.             SendDlgItemMessage( hDlg, IDC_THRESHOLD_SLIDER,    TBM_SETRANGE, FALSE, MAKELONG( DVTHRESHOLD_MIN,  DVTHRESHOLD_MAX ) );
  1049.             SendDlgItemMessage( hDlg, IDC_AGGRESSIVENESS_SLIDER, TBM_SETRANGE, FALSE, MAKELONG( DVBUFFERAGGRESSIVENESS_MIN, DVBUFFERAGGRESSIVENESS_MAX ) );
  1050.  
  1051.             // Setup the dialog based on the globals 
  1052.  
  1053.             // Set the playback controls
  1054.             if( g_dvClientConfig.lPlaybackVolume == DVPLAYBACKVOLUME_DEFAULT )
  1055.             {
  1056.                 CheckRadioButton( hDlg, IDC_PLAYBACK_DEFAULT, IDC_PLAYBACK_SET, IDC_PLAYBACK_DEFAULT );
  1057.             }
  1058.             else
  1059.             {
  1060.                 dwSliderPos = (DWORD) ( ( g_dvClientConfig.lPlaybackVolume - DSBVOLUME_MIN ) * 
  1061.                                           100.0f / (DSBVOLUME_MAX-DSBVOLUME_MIN) );
  1062.                 CheckRadioButton( hDlg, IDC_PLAYBACK_DEFAULT, IDC_PLAYBACK_SET, IDC_PLAYBACK_SET );
  1063.                 SendDlgItemMessage( hDlg, IDC_PLAYBACK_SLIDER, TBM_SETPOS, TRUE, dwSliderPos );
  1064.             }
  1065.  
  1066.             // Set the record controls
  1067.             if( g_dvClientConfig.dwFlags & DVCLIENTCONFIG_AUTORECORDVOLUME )
  1068.             {
  1069.                 CheckRadioButton( hDlg, IDC_RECORD_DEFAULT, IDC_RECORD_AUTO, IDC_RECORD_AUTO );
  1070.             }
  1071.             else if( g_dvClientConfig.lRecordVolume == DVPLAYBACKVOLUME_DEFAULT )
  1072.             {
  1073.                 CheckRadioButton( hDlg, IDC_RECORD_DEFAULT, IDC_RECORD_AUTO, IDC_RECORD_DEFAULT );
  1074.             }
  1075.             else
  1076.             {
  1077.                 dwSliderPos = (DWORD) ( ( g_dvClientConfig.lRecordVolume - DSBVOLUME_MIN ) * 
  1078.                                           100.0f / (DSBVOLUME_MAX-DSBVOLUME_MIN) );
  1079.                 CheckRadioButton( hDlg, IDC_RECORD_DEFAULT, IDC_RECORD_AUTO, IDC_RECORD_SET );
  1080.                 SendDlgItemMessage( hDlg, IDC_RECORD_SLIDER, TBM_SETPOS, TRUE, dwSliderPos );
  1081.             }
  1082.  
  1083.             // Set the threshold controls
  1084.             if( g_dvClientConfig.dwFlags & DVCLIENTCONFIG_AUTOVOICEACTIVATED )
  1085.             {
  1086.                 CheckRadioButton( hDlg, IDC_THRESHOLD_DEFAULT, IDC_THRESHOLD_AUTO, IDC_THRESHOLD_AUTO );
  1087.             }
  1088.             else if( g_dvClientConfig.dwThreshold == DVTHRESHOLD_DEFAULT )
  1089.             {
  1090.                 CheckRadioButton( hDlg, IDC_THRESHOLD_DEFAULT, IDC_THRESHOLD_AUTO, IDC_THRESHOLD_DEFAULT );
  1091.             }
  1092.             else
  1093.             {
  1094.                 CheckRadioButton( hDlg, IDC_THRESHOLD_DEFAULT, IDC_THRESHOLD_AUTO, IDC_THRESHOLD_SET );
  1095.                 SendDlgItemMessage( hDlg, IDC_THRESHOLD_SLIDER, TBM_SETPOS, TRUE, g_dvClientConfig.dwThreshold );
  1096.             }
  1097.  
  1098.             // Set the quality controls
  1099.             if( g_dvClientConfig.dwBufferQuality == DVBUFFERQUALITY_DEFAULT )
  1100.             {
  1101.                 CheckRadioButton( hDlg, IDC_QUALITY_DEFAULT, IDC_QUALITY_SET, IDC_QUALITY_DEFAULT );
  1102.             }
  1103.             else
  1104.             {
  1105.                 CheckRadioButton( hDlg, IDC_QUALITY_DEFAULT, IDC_QUALITY_SET, IDC_QUALITY_SET );
  1106.                 SendDlgItemMessage( hDlg, IDC_QUALITY_SLIDER, TBM_SETPOS, TRUE, g_dvClientConfig.dwBufferQuality );
  1107.             }
  1108.  
  1109.             // Set the aggressiveness controls
  1110.             if( g_dvClientConfig.dwBufferAggressiveness == DVBUFFERAGGRESSIVENESS_DEFAULT )
  1111.             {
  1112.                 CheckRadioButton( hDlg, IDC_AGGRESSIVENESS_DEFAULT, IDC_AGGRESSIVENESS_SET, IDC_AGGRESSIVENESS_DEFAULT );
  1113.             }
  1114.             else
  1115.             {
  1116.                 CheckRadioButton( hDlg, IDC_AGGRESSIVENESS_DEFAULT, IDC_AGGRESSIVENESS_SET, IDC_AGGRESSIVENESS_SET );
  1117.                 SendDlgItemMessage( hDlg, IDC_AGGRESSIVENESS_SLIDER, TBM_SETPOS, TRUE, g_dvClientConfig.dwBufferAggressiveness );
  1118.             }
  1119.  
  1120.             if( !g_bHostPlayer || g_bVoiceSessionInProgress )
  1121.             {
  1122.                 // We are are not the host player then disable all the server only options 
  1123.                 EnableWindow( GetDlgItem( hDlg, IDC_COMPRESSION_COMBO ), FALSE );
  1124.                 EnableWindow( GetDlgItem( hDlg, IDC_SESSIONCOMPRESION_GROUP ), FALSE );
  1125.             }
  1126.             else
  1127.             {
  1128.                 VoiceConfigEnumCompressionCodecs( hDlg );   
  1129.                 EnableWindow( GetDlgItem( hDlg, IDCANCEL ), FALSE );
  1130.             }
  1131.  
  1132.             return TRUE;
  1133.  
  1134.         case WM_NOTIFY:
  1135.             #ifndef NM_RELEASEDCAPTURE
  1136.                 #define NM_RELEASEDCAPTURE (NM_FIRST-16)
  1137.             #endif
  1138.             if( ((LPNMHDR) lParam)->code == NM_RELEASEDCAPTURE )
  1139.             {
  1140.                 // If this is a release capture from a slider, then automatically check 
  1141.                 // its 'Set' radio button.
  1142.                 switch( ((LPNMHDR) lParam)->idFrom )
  1143.                 {
  1144.                 case IDC_PLAYBACK_SLIDER:
  1145.                     CheckRadioButton( hDlg, IDC_PLAYBACK_DEFAULT, IDC_PLAYBACK_SET, IDC_PLAYBACK_SET );
  1146.                     break;
  1147.     
  1148.                 case IDC_RECORD_SLIDER:
  1149.                     CheckRadioButton( hDlg, IDC_RECORD_DEFAULT, IDC_RECORD_AUTO, IDC_RECORD_SET );
  1150.                     break;
  1151.     
  1152.                 case IDC_THRESHOLD_SLIDER:
  1153.                     CheckRadioButton( hDlg, IDC_THRESHOLD_DEFAULT, IDC_THRESHOLD_AUTO, IDC_THRESHOLD_SET );
  1154.                     break;
  1155.     
  1156.                 case IDC_QUALITY_SLIDER:
  1157.                     CheckRadioButton( hDlg, IDC_QUALITY_DEFAULT, IDC_QUALITY_SET, IDC_QUALITY_SET );
  1158.                     break;
  1159.     
  1160.                 case IDC_AGGRESSIVENESS_SLIDER:
  1161.                     CheckRadioButton( hDlg, IDC_AGGRESSIVENESS_DEFAULT, IDC_AGGRESSIVENESS_SET, IDC_AGGRESSIVENESS_SET );
  1162.                     break;
  1163.                 }
  1164.             }
  1165.             return TRUE;            
  1166.  
  1167.         case WM_COMMAND:
  1168.             switch( LOWORD(wParam) )
  1169.             {
  1170.                 case IDOK:
  1171.                     VoiceConfigDlgOnOK( hDlg );
  1172.                     return TRUE;
  1173.  
  1174.                 case IDCANCEL:
  1175.                     EndDialog( hDlg, IDCANCEL );
  1176.                     return TRUE;
  1177.             }
  1178.             break;
  1179.  
  1180.         case WM_DESTROY:
  1181.         {
  1182.             GUID* pGuid;
  1183.             int nCount = (int)SendDlgItemMessage( hDlg, IDC_COMPRESSION_COMBO, CB_GETCOUNT, 0, 0 );
  1184.             for( int i=0; i<nCount; i++ )
  1185.             {
  1186.                 pGuid = (LPGUID) SendDlgItemMessage( hDlg, IDC_COMPRESSION_COMBO, CB_GETITEMDATA, i, 0 );
  1187.                 SAFE_DELETE( pGuid );
  1188.             }
  1189.             break;
  1190.         }
  1191.     }
  1192.  
  1193.     return FALSE; // Didn't handle message
  1194. }
  1195.  
  1196.  
  1197.  
  1198.  
  1199. //-----------------------------------------------------------------------------
  1200. // Name: VoiceConfigEnumCompressionCodecs()
  1201. // Desc: Asks DirectPlayVoice what voice compression codecs are availible
  1202. //       and fills the combo box thier names and GUIDs.
  1203. //-----------------------------------------------------------------------------
  1204. HRESULT VoiceConfigEnumCompressionCodecs( HWND hDlg )
  1205. {
  1206.     LPDIRECTPLAYVOICECLIENT pVoiceClient        = NULL;
  1207.     LPDVCOMPRESSIONINFO     pdvCompressionInfo  = NULL;
  1208.     LPGUID  pGuid         = NULL;
  1209.     LPBYTE  pBuffer       = NULL;
  1210.     DWORD   dwSize        = 0;
  1211.     DWORD   dwNumElements = 0;
  1212.     HWND    hPulldown     = GetDlgItem( hDlg, IDC_COMPRESSION_COMBO );
  1213.     HRESULT hr;
  1214.     LONG    lIndex;
  1215.     LONG    lFirst;
  1216.  
  1217.     CoInitializeEx( NULL, COINIT_MULTITHREADED );
  1218.     if( FAILED( hr = CoCreateInstance( CLSID_DirectPlayVoiceClient, NULL, 
  1219.                                        CLSCTX_INPROC_SERVER, IID_IDirectPlayVoiceClient, 
  1220.                                        (VOID**) &pVoiceClient ) ) )
  1221.         return DXTRACE_ERR( TEXT("CoCreateInstance"), hr );
  1222.  
  1223.     hr = pVoiceClient->GetCompressionTypes( pBuffer, &dwSize, &dwNumElements, 0 );
  1224.     if( hr != DVERR_BUFFERTOOSMALL && FAILED(hr) )
  1225.         return DXTRACE_ERR( TEXT("GetCompressionTypes"), hr );
  1226.  
  1227.     pBuffer = new BYTE[dwSize];
  1228.     if( FAILED( hr = pVoiceClient->GetCompressionTypes( pBuffer, &dwSize, 
  1229.                                                         &dwNumElements, 0 ) ) )
  1230.         return DXTRACE_ERR( TEXT("GetCompressionTypes"), hr );
  1231.  
  1232.     SAFE_RELEASE( pVoiceClient );
  1233.     CoUninitialize();
  1234.  
  1235.     pdvCompressionInfo = (LPDVCOMPRESSIONINFO) pBuffer;
  1236.     for( DWORD dwIndex = 0; dwIndex < dwNumElements; dwIndex++ )
  1237.     {
  1238.         TCHAR strName[MAX_PATH];
  1239.         DXUtil_ConvertWideStringToGeneric( strName, 
  1240.                                            pdvCompressionInfo[dwIndex].lpszName );
  1241.  
  1242.         lIndex = (LONG)SendMessage( hPulldown, CB_ADDSTRING, 0, (LPARAM) strName );
  1243.  
  1244.         pGuid = new GUID;
  1245.         (*pGuid) = pdvCompressionInfo[dwIndex].guidType;
  1246.         SendMessage( hPulldown, CB_SETITEMDATA, lIndex, (LPARAM) pGuid );
  1247.  
  1248.         if( pdvCompressionInfo[dwIndex].guidType == DPVCTGUID_SC03 )
  1249.             lFirst = lIndex;
  1250.     }
  1251.  
  1252.     SAFE_DELETE_ARRAY( pBuffer );
  1253.     SendMessage( hPulldown, CB_SETCURSEL, lFirst, 0 );
  1254.  
  1255.     return S_OK;
  1256. }
  1257.  
  1258.  
  1259.  
  1260.  
  1261. //-----------------------------------------------------------------------------
  1262. // Name: VoiceConfigDlgOnOK()
  1263. // Desc: Figure out all the DirectPlayVoice setup params from the dialog box,
  1264. //       and store them in global vars.
  1265. //-----------------------------------------------------------------------------
  1266. VOID VoiceConfigDlgOnOK( HWND hDlg )
  1267. {
  1268.     DWORD dwSliderPos;
  1269.  
  1270.     g_dvClientConfig.dwFlags = 0;
  1271.  
  1272.     // Figure out the playback params
  1273.     if( IsDlgButtonChecked( hDlg, IDC_PLAYBACK_DEFAULT ) )
  1274.     {
  1275.         g_dvClientConfig.lPlaybackVolume = DVPLAYBACKVOLUME_DEFAULT;
  1276.     }
  1277.     else 
  1278.     {
  1279.         dwSliderPos = (DWORD)SendDlgItemMessage( hDlg, IDC_PLAYBACK_SLIDER, TBM_GETPOS, 0, 0 );
  1280.         g_dvClientConfig.lPlaybackVolume = DSBVOLUME_MIN + (LONG) ( dwSliderPos / 100.0f * 
  1281.                                                                     (DSBVOLUME_MAX-DSBVOLUME_MIN) );
  1282.     }
  1283.  
  1284.     // Figure out the record params
  1285.     if( IsDlgButtonChecked( hDlg, IDC_RECORD_AUTO ) )
  1286.     {
  1287.         g_dvClientConfig.lRecordVolume = 0;
  1288.         g_dvClientConfig.dwFlags       |= DVCLIENTCONFIG_AUTORECORDVOLUME;
  1289.     }
  1290.     else if( IsDlgButtonChecked( hDlg, IDC_RECORD_DEFAULT ) )
  1291.     {
  1292.         g_dvClientConfig.lRecordVolume = DVPLAYBACKVOLUME_DEFAULT;
  1293.     }
  1294.     else 
  1295.     {
  1296.         dwSliderPos = (DWORD)SendDlgItemMessage( hDlg, IDC_RECORD_SLIDER, TBM_GETPOS, 0, 0 );
  1297.         g_dvClientConfig.lRecordVolume = DSBVOLUME_MIN + (LONG) ( dwSliderPos / 100.0f * 
  1298.                                                                   (DSBVOLUME_MAX-DSBVOLUME_MIN) );
  1299.     }
  1300.  
  1301.     // Figure out the threshold params
  1302.     if( IsDlgButtonChecked( hDlg, IDC_THRESHOLD_AUTO ) )
  1303.     {
  1304.         g_dvClientConfig.dwThreshold = DVTHRESHOLD_UNUSED;
  1305.         g_dvClientConfig.dwFlags       |= DVCLIENTCONFIG_AUTOVOICEACTIVATED;
  1306.     }
  1307.     else if( IsDlgButtonChecked( hDlg, IDC_THRESHOLD_DEFAULT ) )
  1308.     {
  1309.         g_dvClientConfig.dwThreshold = DVTHRESHOLD_DEFAULT;
  1310.         g_dvClientConfig.dwFlags       |= DVCLIENTCONFIG_MANUALVOICEACTIVATED;
  1311.     }
  1312.     else 
  1313.     {
  1314.         dwSliderPos = (DWORD)SendDlgItemMessage( hDlg, IDC_THRESHOLD_SLIDER, TBM_GETPOS, 0, 0 );
  1315.         g_dvClientConfig.dwThreshold = dwSliderPos;
  1316.         g_dvClientConfig.dwFlags       |= DVCLIENTCONFIG_MANUALVOICEACTIVATED;
  1317.     }
  1318.  
  1319.     // Figure out the quality params
  1320.     if( IsDlgButtonChecked( hDlg, IDC_QUALITY_DEFAULT ) )
  1321.     {
  1322.         g_dvClientConfig.dwBufferQuality = DVBUFFERQUALITY_DEFAULT;
  1323.     }
  1324.     else 
  1325.     {
  1326.         dwSliderPos = (DWORD)SendDlgItemMessage( hDlg, IDC_QUALITY_SLIDER, TBM_GETPOS, 0, 0 );
  1327.         g_dvClientConfig.dwBufferQuality = dwSliderPos;
  1328.     }
  1329.  
  1330.     // Figure out the aggressiveness params
  1331.     if( IsDlgButtonChecked( hDlg, IDC_AGGRESSIVENESS_DEFAULT ) )
  1332.     {
  1333.         g_dvClientConfig.dwBufferAggressiveness = DVBUFFERAGGRESSIVENESS_DEFAULT;
  1334.     }
  1335.     else 
  1336.     {
  1337.         dwSliderPos = (DWORD)SendDlgItemMessage( hDlg, IDC_AGGRESSIVENESS_SLIDER, TBM_GETPOS, 0, 0 );
  1338.         g_dvClientConfig.dwBufferAggressiveness = dwSliderPos;
  1339.     }
  1340.  
  1341.     if( g_bHostPlayer )
  1342.     {
  1343.         // Figure out the compression codec
  1344.         LONG lCurSelection;
  1345.         LPGUID pGuidCT;
  1346.  
  1347.         lCurSelection = (LONG)SendDlgItemMessage( hDlg, IDC_COMPRESSION_COMBO, CB_GETCURSEL, 0, 0 );
  1348.         if( lCurSelection != CB_ERR )
  1349.         {
  1350.             pGuidCT = (LPGUID) SendDlgItemMessage( hDlg, IDC_COMPRESSION_COMBO, 
  1351.                                                    CB_GETITEMDATA, lCurSelection, 0 );
  1352.             if( pGuidCT != NULL )
  1353.                 g_guidDVSessionCT = (*pGuidCT);
  1354.         }
  1355.     }
  1356.  
  1357.     EndDialog( hDlg, IDOK );
  1358. }
  1359.  
  1360.  
  1361.  
  1362.  
  1363.